package com.raycloud.erp.omll.provider.utils;

import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpUtil;
import cn.hutool.http.Method;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.omall.open.sdk.OmallPageResponse;
import com.omall.open.sdk.OmallResponse;
import com.raycloud.erp.omll.data.entity.MulPlatformUser;
import com.raycloud.erp.omll.provider.config.RequestConfig;
import com.raycloud.erp.omll.provider.constant.Constants;
import com.raycloud.erp.omll.provider.constant.OmallAppInfo;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * 请求工具
 * <p>
 * url:为请求的域名后面需要拼接的部分url参数,如果是需要签名参数url则应该在签名之后参数拼接后使用
 * hearderMap:请求头中需要添加的参数
 * clazz:需要转化的实体类对象
 * map:请求参数map集合
 *
 * @author 枫伦
 * @DESCRIPTION
 * @create 2021/1/6 10:09 上午
 */
@Component
public class OmallHttpUtils {
    @Autowired
    private RequestConfig requestConfig;


    /**
     * http无参数get请求,url为接口的地址
     *
     * @param url
     * @return
     */
    public OmallResponse getWithoutParams(String url, Map<String, String> headerMap, Class<? extends OmallResponse> clazz) {
        HttpRequest get = HttpUtil.createGet(new StringBuilder(requestConfig.getRequestAddr() + url).toString());
        setRequestHeader(headerMap, get);
        HttpResponse execute = get.execute();
        OmallResponse omallResponse = this.resolveResponse(execute.body(), clazz);
        return omallResponse;
    }

    /***
     * @DESCRIPTION: 设置请求头
     * @author 枫伦
     * @params: [headerMap, get]
     * @return: void
     * @Date: 2021/1/6 3:11 下午
     * @Modified By:
     */
    private void setRequestHeader(Map<String, String> headerMap, HttpRequest get) {
        if (!Objects.isNull(headerMap)) {
            for (String key : headerMap.keySet()) {
                get.header(key, headerMap.get(key));
            }
        }
    }

    /***
     * @DESCRIPTION: 不同的平台可能有不同的content-type.这力通过判断不同的content-type来判断是传form表单还是传json串(body)
     * @author 枫伦
     * @params: [headerMap, get, map]
     * @return: void
     * @Date: 2021/1/7 4:20 下午
     * @Modified By:
     */
    private void setRequestHeader(Map<String, String> headerMap, HttpRequest request, Map<String, Object> map) {
        if (!Objects.isNull(headerMap)) {
            for (String key : headerMap.keySet()) {
                request.header(key, headerMap.get(key));
            }
            //content-type为application/json
            if (MediaType.APPLICATION_JSON_VALUE.equalsIgnoreCase(headerMap.get(HttpHeaders.CONTENT_TYPE))) {
                request.body(JSON.toJSONString(map));
            } else {
                //content-type为application/x-www-form-urlencoded
                map.entrySet().stream().forEach(entry -> {
                    request.form(entry.getKey(), entry.getValue());
                });
            }

        }

    }

    /**
     * http有参数get请求
     *
     * @param url 为接口的地址
     * @param map 请求需要的参数
     * @return
     */
    public OmallResponse getWithParams(String url, Map<String, String> headerMap, Class<? extends OmallResponse> clazz, Map<String, Object> map) {
        HttpRequest get = HttpUtil.createGet(new StringBuilder(requestConfig.getRequestAddr() + url).toString());
        setRequestHeader(headerMap, get);
        map.entrySet().stream().forEach(entry -> {
            get.form(entry.getKey(), entry.getValue());
        });
        HttpResponse execute = get.execute();
        OmallResponse omallResponse = this.resolveResponse(execute.body(), clazz);
        return omallResponse;
    }

    /**
     * post,delete,put等无参请求的发送
     *
     * @param method 请求方式
     * @param url    请求地址
     * @return
     */
    public OmallResponse requestWithoutParams(Method method, String url, Map<String, String> headerMap, Class<? extends OmallResponse> clazz) {
        HttpRequest request = HttpUtil.createRequest(method, new StringBuilder(requestConfig.getRequestAddr() + url).toString());
        setRequestHeader(headerMap, request);
        OmallResponse omallResponse = this.resolveResponse(request.execute().body(), clazz);
        return omallResponse;
    }

    /**
     * post,delete,put等有参请求的发送
     *
     * @param method 请求方式
     * @param url    请求地址
     * @param map    请求参数
     * @return
     */
    public OmallResponse requestWithParams(Method method, String url, Map<String, String> headerMap, Class<? extends OmallResponse> clazz, Map<String, Object> map) {
        HttpRequest request = HttpUtil.createRequest(method, new StringBuilder(requestConfig.getRequestAddr() + url).toString());
        setRequestHeader(headerMap, request, map);
        HttpResponse execute = request.execute();
        OmallResponse omallResponse = resolveResponse(execute.body(), clazz);
        return omallResponse;
    }

    /***
     * @DESCRIPTION: 获取平台分页接口的页数和行数
     * @author 枫伦
     * @params: [method, url, headerMap, map]
     * @return: com.omall.open.sdk.OmallResponse
     * @Date: 2021/1/12 11:44 下午
     * @Modified By:  
     */
    public OmallResponse getPageArgs(Method method, String url, Map<String, String> headerMap, Map<String, Object> map) {
        HttpRequest request = HttpUtil.createRequest(method, new StringBuilder(requestConfig.getRequestAddr() + url).toString());
        setRequestHeader(headerMap, request, map);
        HttpResponse execute = request.execute();
        OmallPageResponse omallPageResponse = new OmallPageResponse();
        if (StringUtils.isNotBlank(execute.body())) {
            JSONObject jsonObject = JSONObject.parseObject(execute.body());
            if (StringUtils.isNotBlank(String.valueOf(jsonObject.get("totalPage"))) && StringUtils.isNotBlank(String.valueOf(jsonObject.get("totalRow")))) {
                omallPageResponse.setTotalPage((Integer) jsonObject.get("totalPage"));
                omallPageResponse.setTotalRow((Integer) jsonObject.get("totalRow"));
            }
        }
        return omallPageResponse;
    }

    /**
     * 解析响应内容
     *
     * @param rps
     * @param <T>
     * @return
     */
    public <T extends OmallResponse> T resolveResponse(String rps, Class<? extends OmallResponse> clazz) {
        //实例化接收的javaBean对象
        T response = null;
        try {
            response = (T) clazz.newInstance();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        response.setBody(rps);

        JSONObject root = JSON.parseObject(rps);
        String code = root.getString("code");
        //结果判断
        if (!"100".equals(code)) {
            response.setSuccess(false);
            response.setErrorCode(code);
            response.setErrorMessage(root.getString("message"));
            return response;
        }
        response.setErrorCode(code);
        response.setSuccess(true);
        String dataStr = root.getString("data");
        if (StringUtils.isNotEmpty(dataStr)) {
            //判断接收的数据类型是否为空
            if (response.getResultType() != null) {
                if (JSON.isValidArray(dataStr)) {
                    //是数组
                    List<?> resultArr = JSON.parseArray(dataStr, response.getResultType());
                    response.setResult(resultArr);
                } else {
                    //是对象
                    if (response.getResultType() == String.class) {
                        //这个地方专门处理获取access_token的接口
                        response.setResult(dataStr);
                    } else {
                        Object resultObj = JSON.parseObject(dataStr, response.getResultType());
                        response.setResult(resultObj);
                    }
                }
            }
        } else {
            response.setResult(root.getString("msg"));
        }
        return response;
    }

    /***
     * 功能描述: 判断对象是布尔值或者是数字<br>
     */
    private boolean isBooleanOrNumber(Object object) {
        return object.equals(true) || object.equals(false) || isNumber(object);
    }


    /**
     * 对象转map
     */
    public Map<String, Object> Obj2Map(Object obj) {
        Map<String, Object> map = new HashMap<String, Object>();
        Field[] fields = obj.getClass().getDeclaredFields();
        for (Field field : fields) {
            field.setAccessible(true);
            try {
                if (!ObjectUtils.isEmpty(field.get(obj))) {
                    map.put(field.getName(), field.get(obj));
                }
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }
        return map;
    }

    /**
     * map 转对象
     *
     * @param map 数据map
     * @param clz 转换对象
     * @return
     * @throws Exception
     */
    public Object map2Obj(Map<String, Object> map, Class<?> clz) throws Exception {
        if (map.isEmpty()) {
            throw new RuntimeException("转换的数据map数据对象不能为空");
        }
        Object obj = clz.newInstance();
        Field[] declaredFields = obj.getClass().getDeclaredFields();
        for (Field field : declaredFields) {
            int mod = field.getModifiers();
            if (Modifier.isStatic(mod) || Modifier.isFinal(mod)) {
                continue;
            }
            field.setAccessible(true);
            /*Class<?> type = field.getType();
            Class<?> aClass = map.get(field.getName()).getClass();
            System.out.println(type.equals(aClass));*/
            field.set(obj, map.get(field.getName()));
        }
        return obj;
    }

    /**
     * 判断一个对象是否可以转为数字
     *
     * @param obj
     * @return
     */
    public boolean isNumber(Object obj) {
        if (obj instanceof Number) {
            return true;
        } else if (obj instanceof String) {
            try {
                Double.parseDouble((String) obj);
                return true;
            } catch (Exception e) {
                return false;
            }
        }
        return false;
    }

    /***
     * @DESCRIPTION: 获取请求头Map集合
     * @author 枫伦
     * @params: [user]
     * @return: java.util.Map
     * @Date: 2021/1/10 8:30 下午
     * @Modified By:  
     */
    public Map getHeadMap(MulPlatformUser user) {
        Map<String, String> headMap = new HashMap<>();
        headMap.put(Constants.HEADER_TOKEN_STR, user.getToken());
        headMap.put(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);
        return headMap;
    }

    /***
     * @DESCRIPTION: omall认证字段map
     * @author 枫伦
     * @params: [jsonObject]
     * @return: void
     * @Date: 2021/1/14 5:33 下午
     * @Modified By:
     */
    public Map<String, Object> getAuthMap(MulPlatformUser user) {
        JSONObject jsonObject = JSONObject.parseObject(user.getAuthFieldList());
        Map<String, Object> map = new HashMap<>();
        map.put(OmallAppInfo.STR_APP_KEY, jsonObject.getString(OmallAppInfo.STR_APP_KEY));
        map.put(OmallAppInfo.STR_APP_SECRET, jsonObject.get(OmallAppInfo.STR_APP_SECRET));
        return map;
    }
}
